/*
 * JniFileMethodImplementation.java  0.4.0 / Nov 6, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
package com.cute4j.tools.ng.jni;

import java.io.PrintWriter;

import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaParameter;

import com.cute4j.tools.ng.AbstractNativeFile;
import com.cute4j.tools.ng.NativeGenerator;
import com.cute4j.tools.ng.Utils;

/**
 * JNI File Method Implementation.
 *
 * @author Slobodan Vrkacevic
 * @version 0.4.0
 */
public class JniFileMethodImplementation extends JniFileMethod {

// Private Fields. -------------------------------------------------------------

  private final String body;

// Public Constructors. --------------------------------------------------------

  /**
   * Constructs new JniFileMethod object.
   *
   * @param nativeFile the native file
   * @param method the java method
   * @param overridden <tt>true</tt> if the method is overridden
   */
  public JniFileMethodImplementation(AbstractNativeFile nativeFile,
                                     JavaMethod method, boolean overridden) {
    super(nativeFile, method, overridden);
    this.body = getBody(method);
  }

// Overridden Methods. ---------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  protected String[] getMethodParameters(JavaMethod javaMethod) {
    JavaParameter[] params = javaMethod.getParameters();
    String[] args = new String[params.length + 2];
    String code = Utils.getNativeTagParameter(javaMethod, "code");
    if (Utils.parameterUsed(code, "env")) {
      args[0] = "JNIEnv *env";
    } else {
      args[0] = "JNIEnv *";
    }
    if (javaMethod.isStatic()) {
      if (Utils.parameterUsed(code, "cls")) {
        args[1] = "jclass cls";
      } else {
        args[1] = "jclass";
      }
    } else {
      if ("_create".equals(javaMethod.getName())) {
        args[1] = "jobject obj";
      } else {
        args[1] = "jobject";
      }
    }
    for (int i = 0; i < params.length; i++) {
      if (Utils.parameterUsed(code, params[i].getName())) {
        args[i + 2] = Utils.getJniType(params[i].getType()) + " " +
                      params[i].getName();
      } else {
        args[i + 2] = Utils.getJniType(params[i].getType());
      }
    }
    return args;
  }

  /**
   * {@inheritDoc}
   */
  protected void storeBody(PrintWriter pw) {
    pw.println();
    pw.println("{");
    pw.print("  ");
    pw.println(body);
    pw.println("}");
  }

// Private Static Methods. -----------------------------------------------------

  private static String getBody(JavaMethod method) {
    StringBuffer sb = new StringBuffer();
    String code = Utils.getNativeTagParameter(method, "code");
    if (code == null) {
      if (NativeGenerator.generateDelegate(method.getParentClass())) {
        if (!"void".equals(method.getReturns().getValue())) {
          sb.append("return ");
        }
        int startParamIndex = 1;
        if (method.isStatic()) {
          sb.append(Utils.getDelegateName(method.getParentClass()));
          sb.append(':'); // NOPMD
          sb.append(':'); // NOPMD
          sb.append(Utils.getDelegateMethodName(method));
        } else if ("_create".equals(method.getName())) {
          sb.append(Utils.getDelegateName(method.getParentClass()));
          sb.append("::newInstance");
          startParamIndex = 0;
        } else {
          String delegateObject = Utils.getNativeTagParameter(method,
                                                            "delegateObject");
          if (delegateObject == null) {
            delegateObject = Utils.getDelegateObjectMacro(method.getParentClass());
          }
          sb.append(delegateObject);
          sb.append('-'); // NOPMD
          sb.append('>'); // NOPMD
          sb.append(Utils.getDelegateMethodName(method));
        }
        sb.append("(env");
        if (method.isStatic()) {
          startParamIndex = 0;
          sb.append(", cls");
        } else if ("_create".equals(method.getName())) {
          sb.append(", obj");
        }
        JavaParameter[] params = method.getParameters();
        for (int i = startParamIndex; i < params.length; i++) {
          sb.append(','); // NOPMD
          sb.append(' '); // NOPMD
          sb.append(params[i].getName());
        }
        sb.append(')'); // NOPMD
        sb.append(';'); // NOPMD
      } else {
        if (!"void".equals(method.getReturns().getValue())) {
          sb.append("return 0;");
        }
      }
    } else {
      sb.append(code);
    }
    return sb.toString();
  }

}
